package com.yanqu.road.server.logic.thread;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eMeiTuanActivityChannel;
import com.yanqu.road.entity.enums.eMeiTuanTaskType;
import com.yanqu.road.entity.task.UserTaskData;
import com.yanqu.road.logic.config.ChannelConfig;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.logic.task.BaseCondition;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.executor.GeneralTask;
import com.yanqu.road.utils.http.HttpHelper;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.*;

public class MeiTuanTask extends GeneralTask {
    private Logger logger = LogManager.getLogger(MeiTuanTask.class.getName());

    private GamePlayer player;
    private String appExt;
    private BaseCondition baseCondition;
    private UserTaskData task;

    public MeiTuanTask(GamePlayer player, String appExt, BaseCondition baseCondition, UserTaskData task) {
        super();

        this.player = player;
        this.appExt = appExt;
        this.baseCondition = baseCondition;
        this.task = task;
    }

    @Override
    public void doRun() {
        if(!"meituan2".equals(player.getAppId())) {
            return;
        }
        int paramsOne = 0;
        if(baseCondition.getTaskConditionInfo().getParamList().size() > 0) {
            paramsOne = baseCondition.getTaskConditionInfo().getParamList().get(0).intValue();
        }
        String actionCode;
        if(baseCondition.getTaskConditionInfo().getType() == eGamePlayerEventType.BanquetJoinTimes.getValue()){
               actionCode = "jwdzg_game_fuyan_5";
        }else {
            eMeiTuanTaskType taskType = eMeiTuanTaskType.geteMeiTuanTaskTypeByType(baseCondition.getTaskConditionInfo().getType());
            if (taskType == null) {
                return;
            }
            if (!taskType.isExtend()) {
                actionCode = taskType.getTaskSign();
            } else {
                actionCode = eMeiTuanActivityChannel.getActivityChannelCode(paramsOne);
            }
            if (StringUtils.isNullOrEmpty(actionCode)) {
                logger.info("MeiTuanTask userId:{},actionCode:{}", player.getUserId(), actionCode);
                return;
            }
        }


        long currentTime = DateHelper.getCurrentTime();
        String signType = "SHA1";
        String encryptType = "AES-256-GCM";
        SortedMap<String, String> paramMap = new TreeMap<>();
        try {
            paramMap.put("clientId", ChannelConfig.MEI_TUAN_REPORT_CLIENT_ID);
            paramMap.put("ts", String.valueOf(currentTime));
            paramMap.put("signType", signType);
            paramMap.put("encryptType", encryptType);
            //随机字符串
            paramMap.put("nonce", String.valueOf(RandomHelper.nextLong(1000000)));

            Map<String, String> contentMap = new HashMap<>();
            contentMap.put("mgcId", appExt);
            contentMap.put("actionCode", actionCode);
            contentMap.put("actionFinishTime", DateHelper.getCurrentDateTimeString(currentTime));
            //数据全局唯一标识
            contentMap.put("gameSn", player.getUserId() + "_" + task.getTaskId());

            Map<String, String> contentTreeMap = new TreeMap<>();
            for (Map.Entry<String, String> entry : contentMap.entrySet()) {
                contentTreeMap.put(entry.getKey(), entry.getValue());
            }

            StringBuilder bizContent = new StringBuilder();
            for (Map.Entry<String, String> dataEntry : contentTreeMap.entrySet()) {
                String key = dataEntry.getKey();
                String value = dataEntry.getValue();
                value = URLEncoder.encode(value, "UTF-8");
                value = value.replace("+", "%20");
                bizContent.append(key).append("=").append(value).append("&");
            }
            if (bizContent.length() > 0) {
                bizContent.deleteCharAt(bizContent.length() - 1);
            }

            StringBuilder signData = new StringBuilder(bizContent.toString());
            String uri = ChannelConfig.MEI_TUAN_REPORT_URL.replace("https://mgc.meituan.com/mgc/gateway", "");
            signData.append(String.format("&uri=%s", URLEncoder.encode(uri, "UTF-8")));
            signData.append("&method=POST");
            signData.append(String.format("&secret=%s", ChannelConfig.MEI_TUAN_REPORT_APP_SECRET));

            String secretKey = createKey(ChannelConfig.MEI_TUAN_REPORT_CLIENT_ID + "&" + ChannelConfig.MEI_TUAN_REPORT_APP_SECRET);

            String bizContentJson = JSON.toJSONString(contentMap);

            String signature = encryptSHA1Str(signData.toString() + secretKey);
            paramMap.put("sign", signature);
//            logger.error("MeiTuanTask signData {}", signData.toString());
//            logger.error("MeiTuanTask signData sign {}", paramMap.get("sign"));

            paramMap.put("bizContent", encryptWithAESGCM256(secretKey, bizContentJson.getBytes(StandardCharsets.UTF_8)));
//            logger.error("MeiTuanTask bizContentJson {}", bizContentJson);
//            logger.error("MeiTuanTask bizContentJson encrypted {}", paramMap.get("bizContent"));
        } catch (UnsupportedEncodingException e) {
            logger.error("MeiTuanTask userId:{},actionCode:{},error:", player.getUserId(), actionCode, e);
        }

        try {
            String url = ChannelConfig.MEI_TUAN_REPORT_URL;
            // 空的就不发
            if(StringUtils.isNullOrEmpty(url)) {
                return;
            }
            synchronized (task) {
                if (task.getState() == 0) {
                    Map<String, String> map = HttpHelper.httpPostJson(url, JSON.toJSONString(paramMap), "UTF-8", null, 5000, 5000, 5000);
                    String code = map.getOrDefault("code", "0");
                    if(!"200".equals(code)){
                        logger.error("MeiTuanTask {}", map);
                    }else {
                        JSONObject jsonObject = JSONObject.parseObject(map.getOrDefault("body", ""));
                        if (jsonObject.containsKey("code") && jsonObject.getIntValue("code") == 0) {
                            changeState();
                            logger.info("MeiTuanTask userId:{},actionCode:{},code:{},msg:{}", player.getUserId(), actionCode,
                                    jsonObject.getIntValue("code"), jsonObject.getString("msg"));
                        }else {
                            logger.error("MeiTuanTask result body {}", jsonObject);
                            logger.error("MeiTuanTask url:{}, data: {}", url, JSON.toJSONString(paramMap));
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("MeiTuanTask userId:{},actionCode:{},error:", player.getUserId(), actionCode, e);
        }
    }

    // 设置条件状态移除条件设置
    private void changeState(){
        task.setState(1);
        task.setFinishTime(System.currentTimeMillis() / 1000);
        if (null != baseCondition) {
            baseCondition.removeTrigger(player);
        }
    }

    /**
     * 生成对称密钥
     * @param password  应用id&应用key
     * @return
     */
    public static String createKey(String password) {
        try {
            byte[] keyBytes = password.getBytes(StandardCharsets.UTF_8);
            MessageDigest sha = MessageDigest.getInstance("SHA-1");
            keyBytes = sha.digest(keyBytes);
            keyBytes = Arrays.copyOf(keyBytes, 32);
            SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
            return Base64.getEncoder().encodeToString(secretKey.getEncoded());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 签名
     * @param text 内容
     * @return
     */
    public static String encryptSHA1Str(String text) {
        byte[] bytes = encryptSHA(text, "SHA-1");
        return byte2hex(bytes);
    }

    private static byte[] encryptSHA(String text, String algorithm) {
        MessageDigest md;
        try {
            md = MessageDigest.getInstance(algorithm);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException(e);
        }

        byte[] infoBytes = text.getBytes(StandardCharsets.UTF_8);
        md.update(infoBytes);
        return md.digest();
    }

    private static String byte2hex(byte[] bytes) {
        StringBuilder stringBuilder = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(b & 0xFF);
            if (hex.length() == 1) {
                stringBuilder.append("0");
            }

            stringBuilder.append(hex);
        }

        return stringBuilder.toString();
    }

    private static final String ALGORITHM = "AES";
    private static final String ALGORITHM_PADDING = "AES/GCM/NoPadding";
    private static final int AES_KEY_LENGTH_BIT = 256;
    public static final int GCM_NONCE_LENGTH_BIT = 128;
    public static final int GCM_TAG_LENGTH_BIT = 128;

    /**
     * 加密
     * @param key 密钥
     * @param content 内容
     * @return
     */
    public static String encryptWithAESGCM256(String key, byte[] content) {

        try {
            byte[] keyBytes = Base64.getDecoder().decode(key.getBytes(StandardCharsets.UTF_8));
            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, ALGORITHM);

            Cipher cipher = Cipher.getInstance(ALGORITHM_PADDING, "SunJCE");

            SecureRandom random = SecureRandom.getInstance("NativePRNGNonBlocking");
            final byte[] nonceBytes = new byte[GCM_NONCE_LENGTH_BIT / 8];
            random.nextBytes(nonceBytes);
            GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH_BIT, nonceBytes);

            cipher.init(Cipher.ENCRYPT_MODE, secretKey, spec);
            byte[] contentBytes = cipher.doFinal(content);

            byte[] finalBytes = new byte[nonceBytes.length + contentBytes.length];
            System.arraycopy(nonceBytes, 0, finalBytes, 0, nonceBytes.length);
            System.arraycopy(contentBytes, 0, finalBytes, nonceBytes.length, contentBytes.length);
            String result = new String(Base64.getUrlEncoder().encode(finalBytes), StandardCharsets.UTF_8);
            return result;
        } catch (Exception e) {
            getLOGGER().error("encrypt error", e);
        }

        return null;
    }
}
